<script>
import { parseSi, formatSi, UNITS, FRACTIONAL } from '@/utils/units';
import LabeledInput from '@/components/form/LabeledInput';
import { _EDIT } from '@/config/query-params';

export default {
  components: { LabeledInput },

  props: {
    // Convert output to string
    // Output will also be a string regardless of this prop if outputModifer = true
    outputAs: {
      type:    String,
      default: 'number',
    },

    /* Append exponential modifier in output, eg "123Mi"
      If this is false while inputExponent is true, the output val will be converted to base units
      eg user is views in terms of MiB but integer values corresponding to B are actually emitted
    */
    outputModifier: {
      type:    Boolean,
      default: false
    },

    /* Set modifier on base unit - positive vals map to UNITS array, negative to FRACTIONAL
      String input values with si notation will be converted to this measurement unit,
      eg "1Gi" will become "1024Mi" if this is set to 2
      UNITS = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'];
      FRACTIONAL = ['', 'm', 'u', 'n', 'p', 'f', 'a', 'z', 'y'];
    */
    inputExponent: {
      type:    Number,
      default: 0,
    },

    /* Combines with inputExponent to make displayed unit.
      Use 'suffix' if the input's units are strictly for display
    */
    baseUnit: {
      type:    String,
      default: 'B',
    },

    // If set to 1024, binary modifier will be used eg MiB instead of MB
    increment: {
      type:    Number,
      default: 1000,
    },

    /* Ignore baseUnit and inputExponent in favor of a display-only suffix
        display/emit integers without SI conversion
    */
    suffix: {
      type:    String,
      default: null,
    },

    // LabeledInput props
    mode: {
      type:    String,
      default: _EDIT
    },

    value: {
      type:    [Number, String],
      default: null
    },

    label: {
      type:     String,
      default: null
    },

    labelKey: {
      type:     String,
      default: null
    },

    tooltip: {
      type:    [String, Object],
      default: null
    },

    tooltipKey: {
      type:     String,
      default: null
    },

    required: {
      type:    Boolean,
      default: false,
    },

    min: {
      type:    [Number, String],
      default: 0
    },

    placeholder: {
      type:    [String, Number],
      default: ''
    },
  },

  computed: {
    addon() {
      if (!this.suffix) {
        return false;
      }

      return this.unit + this.suffix;
    },

    unit() {
      let out;

      if ( this.inputExponent >= 0 ) {
        out = UNITS[this.inputExponent];
      } else {
        out = FRACTIONAL[-1 * this.inputExponent];
      }
      if (this.increment === 1024 && out) {
        out += 'i';
      }

      return out;
    },

    // Parse string with unit modifier to base unit eg "1m" -> 0.001
    parsedValue() {
      return typeof this.value === 'string' ? parseSi(this.value) : this.value;
    },

    // Convert integer value
    displayValue() {
      let displayValue = '';

      if ( this.parsedValue || this.parsedValue === 0) {
        displayValue = formatSi(this.parsedValue, {
          increment:        this.increment,
          addSuffix:        false,
          maxExponent:      this.inputExponent,
          minExponent:      this.inputExponent,
        });
      }

      return displayValue ;
    },

    displayUnit() {
      if (this.suffix) {
        return this.suffix;
      }

      return this.unit + this.baseUnit;
    }
  },

  methods: {
    update(inputValue) {
      let out = inputValue === '' ? null : inputValue;

      if (this.outputModifier) {
        out = out === null ? null : `${ inputValue }${ this.unit }`;
      } else if ( this.outputAs === 'string' ) {
        out = out === null ? '' : `${ inputValue }`;
      } else if (out) {
        out = this.unit ? parseSi(`out${ this.unit }`) : parseInt(out);
      }

      this.$emit('input', out);
    },
  }
};
</script>

<template>
  <LabeledInput
    :value="displayValue"
    v-bind="$attrs"
    type="number"
    :min="min"
    :mode="mode"
    :label="label"
    :label-key="labelKey"
    :tooltip="tooltip"
    :tooltip-key="tooltipKey"
    :required="required"
    :placeholder="placeholder"
    @input="update($event)"
  >
    <template #suffix>
      <div v-if="displayUnit" class="addon" :class="{'with-tooltip': tooltip || tooltipKey}">
        {{ displayUnit }}
      </div>
    </template>
  </LabeledInput>
</template>

<style lang="scss" scoped>
  .addon.with-tooltip {
    position: relative;
    right: 30px;
  }
</style>
